package base.thread_example.example06;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * t1线程输出a， t2线程输出b， t3线程输出c，最终输出格式是：循环abc
 *
 * 采用 Object 的 wait, notify 实现
 *
 * Runnable:负责不停调用打印 a,b,c 方法
 *
 * ShareData:负责打印:
 * 1.保存最近一次打印数据,首次要设置保存的数据是打印 a,下一次要打印的是 b
 * 2.根据保存的最近一次数据,判断当前调用者是否就是下一次要打印的数据,然后再次记录 - 打印的是谁,下一个要打印谁;
 *
 */
public class WaitNotify {
    public static void main(String[] args) {
        ShareData sd = new ShareData(1);//1代表首次打印的是a

        Runnable A = new WaitNotifyRunA(sd);
        Runnable B = new WaitNotifyRunB(sd);
        Runnable C = new WaitNotifyRunC(sd);

        new Thread(A,"t1").start();
        new Thread(B,"t2").start();
        new Thread(C,"t3").start();
    }

}

class WaitNotifyRunA implements Runnable {
    private ShareData sd ;
    public WaitNotifyRunA(ShareData sd){
        this.sd = sd;
    }
    @Override
    public void run() {
        while (true){
            try {
                sd.print("a", 1, 2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class WaitNotifyRunB implements Runnable {
    private ShareData sd ;
    public WaitNotifyRunB(ShareData sd){
        this.sd = sd;
    }
    @Override
    public void run() {
        while (true){
            try {
                sd.print("b", 2, 3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class WaitNotifyRunC implements Runnable {
    private ShareData sd ;
    public WaitNotifyRunC(ShareData sd){
        this.sd = sd;
    }
    @Override
    public void run() {
        while (true){
            try {
                sd.print("c", 3, 1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

// 封装共享数据对象

/**
 * 输出内容     当前输出标记    下一个输出标记
 *   a           1             2
 *   b           2             3
 *   c           3             1
 *  1:代表输出a, 2:代表输出b, 3:代表输出c
 */
class ShareData {
    private static final Logger log = LoggerFactory.getLogger(ShareData.class);
    private int currentPrint;// 当前该谁打印标记

    public ShareData(int currentPrint){
        this.currentPrint = currentPrint;
    }

    public synchronized void print(String s, int currentPrint, int nextPrint) throws InterruptedException {
        while (this.currentPrint != currentPrint){
            this.wait();
        }
        log.info("{}:{}", Thread.currentThread().getName(), s);
        this.currentPrint = nextPrint;
        this.notifyAll();
    }
}

